/**
 * @file Serial.cpp
 * @author Beirnaert Simon
 * @brief Definition of the Serial class, declared in Serial.h.
 */

#include "Serial.h"
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
#include <unistd.h>

using namespace std;

Serial::Serial(){
	this->dev=SERIAL_DEVICE;
	this->baudrate=SERIAL_BAUDRATE;
	this->databits=SERIAL_DATABITS;
	this->parity=SERIAL_PARITY;
	this->stopbits=SERIAL_STOPBITS;
	this->flowControl=SERIAL_FLOW_CONTROL;

	this->setUp();
}

Serial::Serial(string dev, int baudrate, int databits, int parity, 
		int stopbits, int flowControl){
	this->dev=dev;
	this->baudrate=baudrate;
	this->databits=databits;
	this->parity=parity;
	this->stopbits=stopbits;
	this->flowControl=flowControl;
	
	this->setUp();
}

Serial::~Serial(){
	close(this->fd);
}

int Serial::setUp(){
	struct termios portAttributes;

	//open port
	if((this->fd = open(this->dev.c_str(), 
				O_RDWR | O_NOCTTY | O_NDELAY)) == -1){
		printf("ERROR: Can't open the port.\n");
		return 1;
	}
	else printf("SUCCESS: port is open!\n");

	//get port attributes
	if(tcgetattr(this->fd, &portAttributes)){
		printf("ERROR: Can't get port attributes.\n");
		return 1;
	}
	else printf("SUCCESS: port attributes get!\n");

	//set the baud rate
	cfsetispeed(&portAttributes, B38400);
	cfsetospeed(&portAttributes, B38400);

	//ignore modem status lines and enable receiving
	portAttributes.c_cflag |= (CLOCAL | CREAD);
	
	if(this->parity)
		//use parity bit
		portAttributes.c_cflag &= PARENB;
	else
		//don't use parity bit
		portAttributes.c_cflag &= ~PARENB;
	
	if(this->stopbits==1)
		//use one stopbit
		portAttributes.c_cflag &= ~CSTOPB;
	else
		//use two stopbits
		portAttributes.c_cflag &= CSTOPB;

	//reset the number of databits first
	portAttributes.c_cflag &= ~CSIZE;
	//then set it accordingly
	switch(this->databits){
		case 5:	portAttributes.c_cflag |= CS5; break;
		case 6:	portAttributes.c_cflag |= CS6; break;
		case 7:	portAttributes.c_cflag |= CS7; break;
		case 8:	portAttributes.c_cflag |= CS8; break;
	}

	//send the new attributes to the port
	if(tcsetattr(this->fd, TCSANOW, &portAttributes) == -1){
		printf("ERROR: Can't set port attributes.\n");
		return 1;
	}
	else printf("SUCCESS: port attributes set!\n");

	return 0;
}

int Serial::swrite(string command){
	const char *temp = command.c_str();
	char cmd[13];
	strncpy(cmd,temp,12);	//never copy more than the destination can 
				//carry
	int len = strlen(cmd);
	cmd[len] = 13;		//add CR
	cmd[len+1] = '\0';	//restore '\0' to complete string

	int written = write(this->fd, cmd, strlen(cmd));
	
	if(written <= 0){
		printf("ERROR: chars written = %d\n", written);
		return -1;
	}

	printf("SUCCESS: executed %s\n", cmd);

	return 0;
}

int Serial::sread(char *result){
	memset(result,'\0',SERIAL_BUF_LEN*sizeof(char));

	//don't block reading from the port
	fcntl(this->fd, F_SETFL, O_NONBLOCK);

	int numRead = read(this->fd, result, SERIAL_BUF_LEN);
	if(numRead < 0){
		printf("ERROR: can't read from serial!\n");
		return -1;
	}

	printf("SUCCESS: read %d chars!\n", numRead);

	return numRead;

}
